package com.hongkuncheng.cms.ueditor.hunter;

import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

import com.hongkuncheng.cms.ueditor.PathFormat;
import com.hongkuncheng.cms.ueditor.define.AppInfo;
import com.hongkuncheng.cms.ueditor.define.BaseState;
import com.hongkuncheng.cms.ueditor.define.MIMEType;
import com.hongkuncheng.cms.ueditor.define.MultiState;
import com.hongkuncheng.cms.ueditor.define.State;
import com.hongkuncheng.cms.ueditor.upload.StorageManager;

/**
 * 图片抓取器
 *
 * @author hancong03@baidu.com
 */
public class ImageHunter {

    private String filename = null;
    private String savePath = null;
    private String rootPath = null;
    private List<String> allowTypes = null;
    private long maxSize = -1;

    private List<String> filters = null;

    public ImageHunter(Map<String, Object> conf) {
        this.filename = (String) conf.get("filename");
        this.savePath = (String) conf.get("savePath");
        this.rootPath = (String) conf.get("rootPath");
        this.maxSize = (Long) conf.get("maxSize");
        this.allowTypes = Arrays.asList((String[]) conf.get("allowFiles"));
        this.filters = Arrays.asList((String[]) conf.get("filter"));
    }

    public State capture(String[] list, HttpServletRequest request) {
        MultiState state = new MultiState(true);
        for (String source : list) {
            state.addState(captureRemoteData(source, request));
        }
        return state;
    }

    public State captureRemoteData(String urlStr, HttpServletRequest request) {
        HttpURLConnection connection = null;
        URL url = null;
        String suffix = null;
        try {
            url = new URL(urlStr);
            if (!validHost(url.getHost())) {
                return new BaseState(false, AppInfo.PREVENT_HOST);
            }
            connection = (HttpURLConnection) url.openConnection();
            connection.setInstanceFollowRedirects(true);
            connection.setUseCaches(true);
            if (!validContentState(connection.getResponseCode())) {
                return new BaseState(false, AppInfo.CONNECTION_ERROR);
            }
            suffix = MIMEType.getSuffix(connection.getContentType());
            if (!validFileType(suffix)) {
                return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
            }
            if (!validFileSize(connection.getContentLength())) {
                return new BaseState(false, AppInfo.MAX_SIZE);
            }
            String savePath = this.getPath(this.savePath, this.filename, suffix, request);
            String physicalPath = this.rootPath + savePath;
            boolean isImage = savePath.indexOf("/image/") != 1;
            State state = StorageManager.saveFileByInputStream(connection.getInputStream(), this.rootPath, physicalPath, isImage);
            if (state.isSuccess()) {
                state.putInfo("url", PathFormat.format(savePath));
                state.putInfo("source", urlStr);
            }
            return state;
        } catch (Exception e) {
            return new BaseState(false, AppInfo.REMOTE_FAIL);
        }
    }

    private String getPath(String savePath, String filename, String suffix, HttpServletRequest request) {
        return PathFormat.parse(savePath + suffix, filename, request);
    }

    private boolean validHost(String hostname) {
        try {
            InetAddress ip = InetAddress.getByName(hostname);
            if (ip.isSiteLocalAddress()) {
                return false;
            }
        } catch (UnknownHostException e) {
            return false;
        }
        return !filters.contains(hostname);
    }

    private boolean validContentState(int code) {
        return HttpURLConnection.HTTP_OK == code;
    }

    private boolean validFileType(String type) {
        return this.allowTypes.contains(type);
    }

    private boolean validFileSize(int size) {
        return size < this.maxSize;
    }

}
